﻿using Kingdee.BOS.Core.Bill;
using Kingdee.BOS.Core.DynamicForm;
using Kingdee.BOS.Core.Metadata.FormElement;
using Kingdee.BOS.Core.Metadata;
using Kingdee.BOS.ServiceHelper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kingdee.BOS;
using Kingdee.BOS.Core.DynamicForm.PlugIn.Args;
using Kingdee.BOS.Core.DynamicForm.PlugIn;
using Kingdee.BOS.Core;
using Kingdee.BOS.Orm.Metadata.DataEntity;
using Kingdee.BOS.Orm.DataEntity;
using Kingdee.BOS.Util;
using Kingdee.BOS.Core.SqlBuilder;
using Kingdee.BOS.Orm;
using Kingdee.BOS.Core.Interaction;
using Kingdee.BOS.Workflow.Models.ServiceArgs;
using Kingdee.BOS.Workflow.Contracts;
using System.Web;
using RK.Model.FanWei;
using Kingdee.BOS.JSON;
using Kingdee.BOS.FileServer.Core.Object;
using Kingdee.BOS.FileServer.ProxyService;
using Newtonsoft.Json;
using System.IO;
using Kingdee.BOS.WebApi.FormService;
using RestSharp;
using Kingdee.BOS.Workflow.ServiceHelper;
using Kingdee.BOS.Workflow.Models.Chart;
using Kingdee.BOS.App.Data;
using System.Transactions;
using Kingdee.BOS.Core.Util;
using Kingdee.BOS.Scripting;
using Kingdee.BOS.Core.DependencyRules;
using Kingdee.BOS.Core.Metadata.Expression.FuncDefine;
using Kingdee.BOS.Core.Metadata.Expression;
using Kingdee.BOS.Web.Bill;
//using System.Reflection;
using System.Runtime.CompilerServices;
using Microsoft.CSharp.RuntimeBinder;
using Kingdee.BOS.Core.Metadata.ConvertElement;
using Kingdee.BOS.Core.DynamicForm.Operation;
using Kingdee.BOS.Core.Metadata.ConvertElement.ServiceArgs;
using Kingdee.BOS.Core.List;
using static Kingdee.K3.FIN.Core.Match.MatchBillFrom.BillEntryKey;

namespace RK.Tools
{
    public static class KingdeeTools
    {
        /// <summary>
        /// 下推服务
        /// </summary>
        /// <param name="ctx">上下文</param>
        /// <param name="sourceFormID">源单formId</param>
        /// <param name="targetFormID">目标单formId</param>
        /// <param name="entryEntityKey">单据体标识</param>
        /// <param name="billTypeID">源单单据类型</param>
        /// <param name="targetBillTypeId">目标单据类型</param>
        /// <param name="primaryKeyValue">源单FID</param>
        /// <param name="entryPrimaryKeyValue">源单分录</param>
        /// <param name="ruleStr">转换规则</param>
        /// <returns></returns>
        public static ConvertOperationResult DzConvertService(Context ctx, string sourceFormID, string targetFormID, string entryEntityKey, string billTypeID, string targetBillTypeId, string primaryKeyValue, string entryPrimaryKeyValue, string ruleStr)
        {
            List<ConvertRuleElement> convertRules = ConvertServiceHelper.GetConvertRules(ctx, sourceFormID, targetFormID);
            var convertRule = convertRules.Find(f => f.Id.Equals(ruleStr));
            List<ListSelectedRow> list2 = new List<ListSelectedRow>();
            Dictionary<string, string> fieldValues = new Dictionary<string, string>();
            fieldValues.Add(entryEntityKey, entryPrimaryKeyValue);
            list2.Add(new ListSelectedRow(primaryKeyValue, entryPrimaryKeyValue, 0, sourceFormID)
            {
                EntryEntityKey = entryEntityKey,
                FieldValues = fieldValues,
                BillTypeID = billTypeID
            });
            PushArgs serviceArgs = new PushArgs(convertRule, list2.ToArray())
            {
                TargetBillTypeId = targetBillTypeId
            };
            OperateOption operateOption = OperateOption.Create();
            //operateOption.SetVariableValue("TransInDetailId", num3);
            ConvertOperationResult operationResult = ConvertServiceHelper.Push(ctx, serviceArgs, operateOption);
            return operationResult;
        }
        /// <summary>
        /// 获取表单的过滤方案名称
        /// </summary>
        /// <param name="ctx">上下文</param>
        /// <param name="formId">单据或账表的标识</param>
        /// <returns></returns>
        public static DynamicObjectCollection GetSchemes(Context ctx, string formId)
        {
            string sql = string.Format(@"/*dialect*/ 
            select FSCHEMENAME from T_BAS_FILTERSCHEME where FFORMID='{0}'  AND FUSERID>0 ", formId);
            DynamicObjectCollection doc = DBUtils.ExecuteDynamicObject(ctx, sql);
            return doc;
        }
        /// <summary>
        /// 保存同步日志记录
        /// </summary>
        /// <param name="context"></param>
        /// <param name="log"></param>
        /// <param name="isAsy">是否异步保存，默认异步</param>
        public static void SaveLog(Context context, SyncLog log, bool isAsy = true)
        {
            List<SqlParam> sqlParams = new List<SqlParam>();
            string sql = "";
            log.GetInsertSqlAndParams(out sqlParams, out sql);
            if (isAsy)
            {
                using (var trans = new KDTransactionScope(TransactionScopeOption.Suppress))
                {
                    int i = DBUtils.Execute(context, sql, sqlParams);
                    if (i > 0)
                    {
                        return;
                    }
                }
            }
            else
            {
                int i = DBUtils.Execute(context, sql, sqlParams);
                if (i > 0)
                {
                    return;
                }
            }
        }
        /// <summary>
        /// 判断字符串是否在枚举中
        /// </summary>
        /// <param name="formId"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public static bool IsStringInEnum(string formId, Type type)
        {
            try
            {
                // 尝试将字符串转换为枚举
                Enum.Parse(type, formId);
                // 如果没有抛出异常，说明字符串在枚举中
                return true;
            }
            catch (ArgumentException)
            {
                // 如果抛出ArgumentException，说明字符串不在枚举中
                return false;
            }
        }
        /// <summary>
        /// 通过用户ID获取用户对应的员工姓名
        /// </summary>
        /// <param name="context"></param>
        /// <param name="creatorId"></param>
        /// <returns></returns>
        public static string GetCreator(Context context, int creatorId)
        {
            string empNumber = "";
            if (creatorId > 0)
            {
                var emp = GetDynamicObjectByFormIdAndId(context, "SEC_User", creatorId);
                if (emp != null)
                {
                    DynamicObject obj = emp["FLinkObject"] as DynamicObject;
                    if (obj != null)
                    {
                        empNumber = obj["number"].ToString();
                    }
                }
            }
            if (!empNumber.IsNullOrEmptyOrWhiteSpace())
            {
                var empinfo = GetDynamicObjectByFormIdAndNumber(context, "BD_Empinfo", empNumber);
                //string dep1 = empinfo["F_PXIA_Text1"] == null ? "" : empinfo["F_PXIA_Text1"].ToString();
                //string dep2 = empinfo["F_PXIA_Text14"] == null ? "" : empinfo["F_PXIA_Text14"].ToString();
                string name = empinfo["name"] == null ? "" : empinfo["name"].ToString();
                return name;
            }
            return "超级管理员";
        }
        /// <summary>
        /// 获取工作流流程实例信息
        /// </summary>
        /// <param name="context">上下文</param>
        /// <param name="formId">单据标识</param>
        /// <param name="fid">单据主键FID</param>
        /// <returns></returns>
        public static object GetWorkflowInfo(Context context, string formId, string fid)
        {
            //获取当前最新流程实例id
            string cprocInstId = WorkflowChartServiceHelper.GetProcInstIdByBillInst(context, formId, fid);
            if (!cprocInstId.IsNullOrEmptyOrWhiteSpace())
            {
                //流程实例
                DynamicObject procInst = GetDynamicObjectByFormIdAndId(context, "WF_ProcInstBill", cprocInstId);
                //流程模板
                DynamicObject tmp = GetDynamicObjectByFormIdAndId(context, "wf_TemplateSelect", procInst["FTmpId_id"]);
                //类型
                string processType = Convert.ToString(tmp["ProcessType"]);
                List<ChartActivityInfo> activityInfos = WorkflowChartServiceHelper.GetProcessRouter(context, cprocInstId);
                ChartActivityInfo chartActivityInfo = activityInfos.Last();
                if (chartActivityInfo.ActionDetails.Count() > 0)
                {
                    foreach (ChartActionInfo chartActionInfo in chartActivityInfo.ActionDetails)
                    {

                    }
                }
            }
            return "";
        }
        /// <summary>
        /// 转换泛微OA的JSON格式
        /// </summary>
        /// <param name="json"></param>
        /// <param name="fPrecondition"></param>
        /// <param name="requestId"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static JSONObject ConvertOAJSON(JSONObject json, string fPrecondition, int requestId)
        {
            //如果修改接口，添加requestId
            if (fPrecondition == "FIsSubSynOA=true" || fPrecondition == "FIsSubSynOA2=true")
            {
                json.Put("requestId", requestId);
            }
            //单据头
            if (json.ContainsKey("mainData"))
            {
                Dictionary<string, object> dic = json.GetJSONObject("mainData");
                JSONArray array = new JSONArray();
                foreach (var k in dic.Keys)
                {
                    object v = dic[k];
                    //附件特殊处理
                    if (v is JSONObject && (v as JSONObject).ContainsKey("filePath"))
                    {
                        JSONObject vo = v as JSONObject;
                        string filePath = vo.GetString("filePath");
                        string fileName = vo.GetString("fileName");
                        JSONObject o = new JSONObject();
                        o.Add("fieldName", k);
                        JSONArray array2 = new JSONArray();
                        JSONObject o2 = new JSONObject();
                        o2.Add("filePath", filePath);
                        o2.Add("fileName", fileName);
                        array2.Add(o2);
                        o.Add("fieldValue", array2);
                        array.Add(o);
                    }
                    else
                    {
                        JSONObject o = new JSONObject();
                        o.Add("fieldName", k);
                        o.Add("fieldValue", v);
                        array.Add(o);
                    }
                }
                json["mainData"] = array;
            }
            //单据体
            if (json.ContainsKey("detailData"))
            {
                JSONArray arr = json.Get("detailData") as JSONArray;
                if (arr.Count > 0)
                {
                    JSONObject firstObj = arr.First() as JSONObject;
                    string tableDBName = "";
                    firstObj.TryGetValue<string>("tableDBName", "", out tableDBName);
                    if (tableDBName.IsNullOrEmptyOrWhiteSpace())
                    {
                        throw new Exception("转OA数据失败，明细'detailData'未设置'tableDBName'!请在同步设置中配置!");
                    }
                    //最上级
                    JSONArray array = new JSONArray();
                    //第二级
                    JSONObject jo = new JSONObject();
                    jo.Add("tableDBName", tableDBName);
                    //如果修改接口，添加deleteAll参数
                    if (fPrecondition == "FIsSubSynOA=true" || fPrecondition == "FIsSubSynOA2=true")
                    {
                        jo.Add("deleteAll", "1");
                    }
                    //第三级
                    int i = 1;
                    JSONArray rows = new JSONArray();
                    foreach (JSONObject a in arr)
                    {
                        JSONObject row = new JSONObject();
                        //row.Add("recordOrder", i);
                        JSONArray array0 = new JSONArray();
                        foreach (var k in a.Keys)
                        {
                            if (k.EqualsIgnoreCase("tableDBName"))
                            {
                                continue;
                            }
                            object v = a[k];
                            JSONObject o = new JSONObject();
                            o.Add("fieldName", k);
                            o.Add("fieldValue", v);
                            array0.Add(o);
                        }
                        row.Add("workflowRequestTableFields", array0);
                        rows.Add(row);
                        i++;
                    }
                    jo.Add("workflowRequestTableRecords", rows);
                    array.Add(jo);
                    json["detailData"] = array;
                }
            }
            return json;
        }
        /// <summary>
        /// 金蝶用户添加自定义字段，关联泛微OA的工号，获取工号
        /// </summary>
        /// <param name="context"></param>
        /// <param name="receiverId"></param>
        /// <returns></returns>
        public static string GetWorkCode(Context context, string receiverId)
        {
            long userId = context.UserId;
            string workcode = "";
            var res = WebApiServiceCall.ExecuteBillQuery(context, QueryParameter("SEC_User", "F_YCVN_GH", $"FUserID={receiverId}"));
            if (res.Count > 0)
            {
                workcode = res.FirstOrDefault().FirstOrDefault().ToString();
            }
            return workcode;
        }

        private static string QueryParameter(string formId, string fieldKeys, string filterString)
        {
            var param = new
            {
                FormId = formId,
                FieldKeys = fieldKeys,
                FilterString = filterString
            };
            return JsonConvert.SerializeObject(param);
        }

        /// <summary>
        /// 从金蝶文件服务获取附件，然后上传到OA的附件
        /// </summary>
        /// <param name="context"></param>
        /// <param name="attachment"></param>
        /// <param name="fileService"></param>
        /// <returns></returns>
        public static string SyncFiles(Context context, DynamicObject attachment, UpDownloadService fileService)
        {
            //获取同步设置和URL
            DynamicObject setting = GetKToOSysSynSetting(context, "", 0);
            string oaUrl = Convert.ToString(setting["OSysURL"]);
            string FOaFilesUrl = Convert.ToString(setting["FOaFilesUrl"]);
            string appkey = Convert.ToString(setting["FOSysURL2"]);
            string workcode = GetWorkCode(context, context.UserId.ToString());
            //金蝶编码
            string billNo = Convert.ToString(attachment["BillNo"]);
            //文件ID
            string fileId = Convert.ToString(attachment["FileId"]);
            //从文件服务器
            if (!fileId.IsNullOrEmptyOrWhiteSpace())
            {
                ////创建日期
                //DateTime createDate = Convert.ToDateTime(attachment["CreateTime"]);
                ////文件后缀
                //string extName = Convert.ToString(attachment["ExtName"]);
                //名称
                string name = Convert.ToString(attachment["AttachmentName"]);
                ////备注
                //string note = Convert.ToString(attachment["AttachmentDes"]);

                TFileInfo tFile = new TFileInfo() { FileId = fileId, CTX = context };
                byte[] fileData = fileService.GetFileData(tFile);
                //var url = fileService.GetFileServiceServerUrl(tFile);
                // 获取或创建临时目录
                string path = HttpContext.Current.Server.MapPath(KeyConst.TEMPFILEPATH);
                //不存在则创建文件目录
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                // 生成一个临时文件名
                string fileName = Path.Combine(path, name);
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
                TFileInfo dFile = new TFileInfo() { FileId = fileId, CTX = context, FilePath = fileName };
                var dfiles = fileService.DownloadSaveLocal(dFile);

                string url = oaUrl + FOaFilesUrl;
                var client = new RestClient(url);
                client.Timeout = -1;
                var request = new RestRequest(RestSharp.Method.POST);
                request.AddHeader("appkey", appkey);
                request.AddHeader("workcode", workcode);
                request.AddParameter("category", "89");
                request.AddFile("file", fileName);
                request.AddParameter("name", name);
                IRestResponse response = client.Execute(request);
                var res = response.Content;
                var oafilRes = JsonConvert.DeserializeObject<OaFilesResult>(res);
                //文件大小
                //long fileSize = fileData.Length;
                //string str = Convert.ToBase64String(fileData);
                string str = oafilRes.data.fileid;
                return str;
            }
            //从数据库
            else
            {
                byte[] fileData = (byte[])attachment["Attachment"];
                string str = Convert.ToBase64String(fileData);
                return str;
            }
        }
        /// <summary>
        /// 根据单据获取单据附件
        /// </summary>
        /// <param name="context"></param>
        /// <param name="formId"></param>
        /// <param name="billId"></param>
        /// <returns></returns>
        public static DynamicObject[] GetAttachments(Context context, string formId, object billId)
        {
            string filterStr = string.Format("FBillType = '{0}' and FInterId IN ('{1}')", formId, billId);
            OQLFilter filter = OQLFilter.CreateHeadEntityFilter(filterStr);
            DynamicObject[] attaDynObjs = BusinessDataServiceHelper.Load(context, FormIdConst.BOS_Attachment, null, filter);
            return attaDynObjs;
        }
        /// <summary>
        /// 获取同步设置，获取组织所有设置，如果存在多行就增加表单Id去找到指定业务对象同步设置
        /// </summary>
        /// <param name="context"></param>
        /// <param name="formId"></param>
        /// <param name="orgId"></param>
        /// <returns></returns>
        public static DynamicObject GetKToOSysSynSetting(Context context, string formId, long orgId)
        {
            FormMetadata meta = MetaDataServiceHelper.GetFormMetaData(context, "qqq_KAndOSysSynSet");
            QueryBuilderParemeter queryParam = new QueryBuilderParemeter();
            queryParam.FormId = "qqq_KAndOSysSynSet";
            //queryParam.FilterClauseWihtKey = string.Format(" FDOCUMENTSTATUS='C' AND FFORBIDSTATUS='A' and FUSEORGID={0}", orgId);
            queryParam.FilterClauseWihtKey = string.Format(" FDOCUMENTSTATUS='C' AND FFORBIDSTATUS='A' ");
            var objs = BusinessDataServiceHelper.Load(context, meta.BusinessInfo.GetDynamicObjectType(), queryParam);
            if (objs.Length > 1)
            {
                var findRows = objs.Where(w => (w["FormId"] as DynamicObject) != null && Convert.ToString((w["FormId"] as DynamicObject)["id"]).EqualsIgnoreCase(formId));
                if (findRows != null && findRows.Count() > 0)
                {
                    return findRows.First();
                }
            }
            else if (objs.Length == 1)
            {
                return objs.First();

            }
            return null;
        }
        /// <summary>
        /// 打开外部链接
        /// </summary>
        /// <param name="view"></param>
        /// <param name="requestid"></param>
        /// <param name="context"></param>
        /// <param name="formid"></param>
        /// <param name="workcode"></param>
        public static void openUrl(IDynamicFormView view, int requestid, Context context, string formid, string workcode)
        {
            //workcode = "ZJRM0313";
            //获取同步设置和URL
            DynamicObject setting = GetKToOSysSynSetting(context, formid, 0);
            string appkey = Convert.ToString(setting["FOSysURL2"]);
            string esbUrl = Convert.ToString(setting["FLct"]);
            string oaUrl = Convert.ToString(setting["FOAURL"]);
            string soTokenUrl = Convert.ToString(setting["FssoToken"]);
            string appid = Convert.ToString(setting["Fappid"]);
            soTokenUrl = soTokenUrl + $"?appid={appid}&loginid={workcode}";
            esbUrl = esbUrl + $"?requestid={requestid}";
            //获取OA流程图Url
            FlowChart result = InvokeHelper.Post(esbUrl, appkey, workcode);
            var chartUrl = result.data.chartUrl;
            //获取ssoToken  FssoToken
            var ssoTokenResult = InvokeHelper.Post(soTokenUrl);
            //拼接流程图url
            oaUrl = oaUrl + chartUrl + $"&ssoToken={ssoTokenResult}";
            //string url = @"http://www.baidu.com";
            // 方式一
            // 直接打开浏览器并跳转到此Url地址
            //ViewCommonAction.ShowWebURL(view, url);
            //view.SendDynamicFormAction(view);

            // 方式二
            // 弹窗打开Url地址
            JSONObject webobj = new JSONObject();
            webobj["source"] = oaUrl;
            webobj["height"] = 600;
            webobj["width"] = 910;

            //默认打开全屏显示
            webobj["isfullscreen"] = true;

            ////是否新弹出一个浏览器窗口（or选项卡）打开网页地址
            webobj["isweb"] = true;

            webobj["title"] = "OA流程图";

            view.AddAction("ShowKDWebbrowseForm", webobj);
            view.SendAynDynamicFormAction(view);
        }
        /// <summary>
        /// 打开待办任务审批
        /// </summary>
        /// <param name="usserName"></param>
        /// <param name="id"></param>
        /// <param name="kingdeeUrl"></param>
        /// <param name="processType"></param>
        /// <returns></returns>
        public static string GetH5KindeeUrl(string usserName, string id, string kingdeeUrl, string processType, Context ctx)
        {
            //获取同步设置和URL
            DynamicObject setting = KAndOSysSynTool.GetKToOSysSynSetting(ctx, "", 0);
            int lcId = 2052;
            long timestamp = CurrentTimeMillis();//时间戳           
            string dbId = Convert.ToString(setting["Faccid"]);
            string appId = Convert.ToString(setting["FKdAppid"]);
            string appSecret = Convert.ToString(setting["FappSecret"]);
            //string dbId = "675155b0270113";
            //string appId = "297624_W27DSdGPUrG/w++O2d0OQ9SFUgxUWrkH";
            //string appSecret = "53269de024d443dbab010ff925e5f192";
            string[] arr = new string[] { dbId, usserName, appId, appSecret, timestamp.ToString() };
            string sign = SHA1Util.GetSignature(arr);//签名      
            SimplePassportLoginArg arg = new SimplePassportLoginArg();
            arg.appid = appId;
            arg.dbid = dbId;
            arg.lcid = lcId.ToString();
            arg.origintype = "SimPas";//XT=云之家集成（同时要求entryrole=XT）；SimPas=简单通行证集成
            arg.signeddata = sign;
            arg.timestamp = timestamp.ToString();
            arg.username = usserName;
            arg.openmode = "Single";// "Single";//登陆后打开指定功能单据的模式，空白=原有主控模式，Single=单独打开指定单据（没有主控功能，仅HTML5端支持，需要配合轻量级入口地址：【http://xxx.xxx.xxx.xxx/k3cloud/html5/lightstartapp.aspx?ud=...】）
            //arg.formid = processType == "310" ? "AP_ApprovalAssignHandleH5" : "WF_AssignmentApprovalH5";//310为审批流
            arg.formid = processType;//310为审批流
            //permitcount：允许登录次数，0 允许重复登录 ，1 只允许登录一次
            //arg.entryrole = string.Empty;//验证权限的入口角色
            //arg.formid = "WF_AssignmentApproval";//登录后默认打开功能的表单id
            arg.formtype = "sysreport";//登录后默认打开功能的格式，单据：bill或空, 列表：list, 万能报表：wnreport, 直接sql报表：sqlreport, 系统报表：sysreport， 树形报表：treereport, 移动报表：movereport， 动态表单：dynamicform
                                       //showParameter.CustomParams.Add("AssignId", assignId);             showParameter.CustomParams.Add("Status", ApprovalItemStatus.UnCompleted.ToString());            showParameter.CustomParams.Add("OperationStatus", Kingdee.BOS.Core.Metadata.OperationStatus.EDIT.ToString());
                                       //formargs: 表单初始化自定义参数formargs，能设置boside中发布的自定义参数。仅V2版本协议支持该参数，V1版本不支持。 formargs为json格式字符串，例如人人报销首页参数：{ "KD_Html5_FormTheme_Name": "Galaxy" } 。
                                       //arg.otherargs = id;//作为用户自定义参数传入，最终在指定表单的插件中通过GetCustomParameter(FormConst.StartAppArgs)获取
                                       //arg.pkid = string.Empty;
            string argJosn = Kingdee.BOS.JSON.KDObjectConverter.SerializeObject(arg);
            string argJsonBase64 = System.Text.UTF8Encoding.UTF8.GetBytes(argJosn).ToBase64();
            string url = kingdeeUrl;
            string html5Url = url + "/html5/Index.aspx?udencoding=utf-8&ud=" + argJsonBase64;// html5入口链接  
            //string html5Url = url + "/html5/Index.aspx?ud=" + argJsonBase64;// html5入口链接  
            return html5Url;
        }
        /// <summary>
        /// 打开待办任务审批
        /// </summary>
        /// <param name="usserName"></param>
        /// <param name="id"></param>
        /// <param name="kingdeeUrl"></param>
        /// <param name="processType"></param>
        /// <returns></returns>
        public static string GetH5KindeeUrl2(string usserName, string id, string kingdeeUrl, string processType)
        {
            int lcId = 2052;
            long timestamp = CurrentTimeMillis();//时间戳           
            string dbId = OAResultConstant.acctId;//数据中心ID           
            //string usserName = "qzy";//用户名称          
            string appId = OAResultConstant.appId;//第三方系统应用Id        
            string appSecret = OAResultConstant.appSecret;//第三方系统应用秘钥      
            string[] arr = new string[] { dbId, usserName, appId, appSecret, timestamp.ToString() };
            string sign = SHA1Util.GetSignature(arr);//签名      
            SimplePassportLoginArg arg = new SimplePassportLoginArg();
            arg.appid = appId;
            arg.dbid = dbId;
            arg.lcid = lcId.ToString();
            arg.origintype = "SimPas";//XT=云之家集成（同时要求entryrole=XT）；SimPas=简单通行证集成
            arg.signeddata = sign;
            arg.timestamp = timestamp.ToString();
            arg.username = usserName;
            arg.openmode = "Single";// "Single";//登陆后打开指定功能单据的模式，空白=原有主控模式，Single=单独打开指定单据（没有主控功能，仅HTML5端支持，需要配合轻量级入口地址：【http://xxx.xxx.xxx.xxx/k3cloud/html5/lightstartapp.aspx?ud=...】）
            arg.formid = processType == "310" ? "AP_ApprovalAssignHandleH5" : "WF_AssignmentApprovalH5";//310为审批流
            //permitcount：允许登录次数，0 允许重复登录 ，1 只允许登录一次
            arg.entryrole = string.Empty;//验证权限的入口角色
            //arg.formid = "WF_AssignmentApproval";//登录后默认打开功能的表单id
            arg.formtype = string.Empty;//登录后默认打开功能的格式，单据：bill或空, 列表：list, 万能报表：wnreport, 直接sql报表：sqlreport, 系统报表：sysreport， 树形报表：treereport, 移动报表：movereport， 动态表单：dynamicform
                                        //showParameter.CustomParams.Add("AssignId", assignId);             showParameter.CustomParams.Add("Status", ApprovalItemStatus.UnCompleted.ToString());            showParameter.CustomParams.Add("OperationStatus", Kingdee.BOS.Core.Metadata.OperationStatus.EDIT.ToString());
                                        //formargs: 表单初始化自定义参数formargs，能设置boside中发布的自定义参数。仅V2版本协议支持该参数，V1版本不支持。 formargs为json格式字符串，例如人人报销首页参数：{ "KD_Html5_FormTheme_Name": "Galaxy" } 。
            arg.otherargs = id;//作为用户自定义参数传入，最终在指定表单的插件中通过GetCustomParameter(FormConst.StartAppArgs)获取
            arg.pkid = string.Empty;
            string argJosn = Kingdee.BOS.JSON.KDObjectConverter.SerializeObject(arg);
            string argJsonBase64 = System.Text.UTF8Encoding.UTF8.GetBytes(argJosn).ToBase64();
            string url = kingdeeUrl;
            string html5Url = url + "/html5/Index.aspx?udencoding=utf-8&ud=" + argJsonBase64;// html5入口链接  
            return html5Url;
        }
        /// <summary>
        /// 打开待办任务列表
        /// </summary>
        /// <param name="username"></param>
        /// <param name="pkId"></param>
        /// <param name="kingdeeUrl"></param>
        /// <returns></returns>
        public static string GetMobileUrl(string username, string pkId, string kingdeeUrl)
        {
            //数据中心Id
            string acctId = OAResultConstant.acctId;
            //用户名
            //string username = "qzy";
            //第三方系统登录授权的应用Id;
            string appId = OAResultConstant.appId;
            //第三方系统登录授权的应用密钥;
            string appSecret = OAResultConstant.appSecret;
            int lcId = 2052; //语言标识 中文：2052，繁体：3067，英文：1033        
            long timestamp = CurrentTimeMillis(); //时间戳        
            string[] arr = new string[] { acctId, username, appId, appSecret, timestamp.ToString() };
            //签名
            string sign = GetSignature(arr);
            //base64编码       
            string sign64 = GetBase64String(appId, username, appSecret, sign, timestamp);
            //金蝶云星空后台设置的系统公网地址 
            string serverUrl = kingdeeUrl;
            //登录成功后打开的表单Id，业务审批列表：Mob_XWfListEdit; 业务审批详情：Mob_DistributionWfBill;
            string formId = "Mob_XWfListEdit";
            //移动单据列表则用formtype = "mobilelist"  
            //string formType = "mobile";
            string formType = "mobile";
            //单据详情主键，如果打开的是业务审批详情，需要传入的是待办任务id
            //string pkId = "66ac8ea44f3c0a";
            string url = GetUrl(serverUrl, acctId, lcId, sign64, formId, formType, pkId);
            return url;
        }
        /// <summary>
        /// 打开待办任务审批
        /// </summary>
        /// <param name="username"></param>
        /// <param name="pkId"></param>
        /// <param name="kingdeeUrl"></param>
        /// <returns></returns>
        public static string GetMobileUrl2(string username, string pkId, string kingdeeUrl)
        {
            //数据中心Id
            string acctId = OAResultConstant.acctId;
            //用户名
            //string username = "qzy";
            //第三方系统登录授权的应用Id;
            string appId = OAResultConstant.appId;
            //第三方系统登录授权的应用密钥;
            string appSecret = OAResultConstant.appSecret;
            int lcId = 2052; //语言标识 中文：2052，繁体：3067，英文：1033        
            long timestamp = CurrentTimeMillis(); //时间戳        
            string[] arr = new string[] { acctId, username, appId, appSecret, timestamp.ToString() };
            //签名
            string sign = GetSignature(arr);
            //base64编码       
            string sign64 = GetBase64String(appId, username, appSecret, sign, timestamp);
            //金蝶云星空后台设置的系统公网地址 
            string serverUrl = kingdeeUrl;
            //登录成功后打开的表单Id，业务审批列表：Mob_XWfListEdit; 业务审批详情：Mob_DistributionWfBill;
            string formId = "Mob_DistributionWfBill";
            //移动单据列表则用formtype = "mobilelist"  
            //string formType = "mobile";
            string formType = "mobile";
            //单据详情主键，如果打开的是业务审批详情，需要传入的是待办任务id
            //string pkId = "66ac8ea44f3c0a";
            string url = GetUrl(serverUrl, acctId, lcId, sign64, formId, formType, pkId);
            return url;
        }

        private static string GetUrl(string serverUrl, string acctId, int lcId, string sign64, string formId, string formType, string pkId)
        {
            string url = string.Format(@"{0}/xmobile/cloud.html?entryrole=oo&acctid={1}&lcid={2}&sign={3}&formid={4}&formtype={5}&pkid={6}", serverUrl, acctId, lcId, sign64, formId, formType, pkId);
            return url;
        }

        private static string GetBase64String(string appId, string username, string appSecret, string sign, long timestamp)
        {
            //下面json中的参数严格区分大小写，请保持一致
            string signInfo = "{'appId':'" + appId + "','username':'" + System.Web.HttpUtility.UrlEncode(username) + "','sign':'" + sign + "','timestamp':" + timestamp + "}";
            byte[] bytes = Encoding.UTF8.GetBytes(signInfo);
            return Convert.ToBase64String(bytes);
        }

        /// <summary>
        /// SHA签名
        /// </summary>
        /// <param name="arr"></param>
        /// <returns></returns>
        private static string GetSignature(string[] arr)
        {
            //1. 将数组进行排序
            //2. 将数组拼接成一个字符串进行sha加密
            Array.Sort(arr, StringComparer.Ordinal);
            var arrString = string.Join("", arr);
            var sha = System.Security.Cryptography.SHA256.Create();
            var shaArr = sha.ComputeHash(Encoding.UTF8.GetBytes(arrString));
            StringBuilder enText = new StringBuilder();
            foreach (var b in shaArr)
            {
                enText.AppendFormat("{0:x2}", b);
            }

            return enText.ToString();
        }

        /// <summary>
        /// 获取时间戳
        /// </summary>
        /// <returns></returns>
        private static long CurrentTimeMillis()
        {
            var janist1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            return (long)((DateTime.UtcNow - janist1970).TotalMilliseconds) / 1000;
        }

        /// <summary>
        /// 获取网站URL
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string GetRequestWebUrl()
        {
            if (HttpContext.Current != null && HttpContext.Current.Request != null)
            {
                HttpRequest request = HttpContext.Current.Request;
                string urlAuthority = request.Url.GetLeftPart(UriPartial.Authority);
                if (request.ApplicationPath == null || request.ApplicationPath == "/")
                {
                    //当前部署在Web站点下
                    return urlAuthority;
                }
                else
                {
                    //当前部署在虚拟目录下
                    return urlAuthority + request.ApplicationPath;
                }
            }
            return "";
        }
        /// <summary>
        /// 判断操作结果是否成功，如果不成功，则直接抛错中断进程
        /// </summary>
        /// <param name="BusinessInfoOperationResult">服务插件的操作结果</param>
        /// <param name="opResult">当前操作结果</param>
        /// <returns></returns>
        public static bool CheckOpResult(IOperationResult BusinessInfoOperationResult, IOperationResult opResult)
        {
            bool isSuccess = false;
            if (opResult.IsSuccess == true)
            {
                // 操作成功
                isSuccess = true;
            }
            else
            {
                if (opResult.InteractionContext != null
                && opResult.InteractionContext.Option.GetInteractionFlag().Count > 0)
                {// 有交互性提示

                    // 传出交互提示完整信息对象
                    BusinessInfoOperationResult.InteractionContext = opResult.InteractionContext;
                    // 传出本次交互的标识，
                    // 用户在确认继续后，会重新进入操作；
                    // 将以此标识取本交互是否已经确认过，避免重复交互
                    BusinessInfoOperationResult.Sponsor = opResult.Sponsor;

                    // 抛出错误，终止本次操作
                    throw new KDBusinessException("", "本次操作需要用户确认是否继续，暂时中断。" + opResult.InteractionContext.SimpleMessage);
                }
                else
                {
                    // 操作失败，拼接失败原因，然后抛出中断
                    opResult.MergeValidateErrors();
                    if (opResult.OperateResult == null)
                    {// 未知原因导致提交失败
                        throw new KDBusinessException("", "未知原因导致自动提交、审核失败！");
                    }
                    else
                    {
                        StringBuilder sb = new StringBuilder();
                        sb.AppendLine("自动提交、审核失败，失败原因：");
                        foreach (var operateResult in opResult.OperateResult)
                        {
                            sb.AppendLine(operateResult.Message);
                        }
                        throw new KDBusinessException("", sb.ToString());
                    }
                }
            }
            return isSuccess;
        }
        /// <summary>
        /// 将操作结果转换成字符串
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        public static string GetOperateResultStr(IOperationResult result)
        {
            List<string> infos = new List<string>();
            if (result.OperateResult != null && result.OperateResult.Count() > 0)
            {
                foreach (var item in result.OperateResult)
                {
                    infos.Add(item.Message);
                }
            }
            if (result.ValidationErrors.Count > 0)
            {
                foreach (var err in result.ValidationErrors)
                {
                    infos.Add(err.Message);
                }
            }
            if (!result.IsSuccess && result.InteractionContext != null && !result.InteractionContext.SimpleMessage.IsNullOrEmptyOrWhiteSpace())
            {
                infos.Add(result.InteractionContext.SimpleMessage);
            }
            return string.Join(";", infos);
        }
        /// <summary>
        /// 提交了工作流，撤销工作流实例
        /// </summary>
        /// <param name="context"></param>
        /// <param name="formId"></param>
        /// <param name="billId"></param>
        /// <returns></returns>
        public static IOperationResult AbortProcInst(Context context, string formId, string billId)
        {
            // 读取待撤销的流程实例
            // using Kingdee.BOS.Workflow.Models.ServiceArgs;
            GetCancelAssignsArgs getCancelAssignsArgs = new GetCancelAssignsArgs();
            getCancelAssignsArgs.GetByBill(formId, billId);
            IAssignmentService assignService = Kingdee.BOS.Workflow.Contracts.ServiceFactory.GetAssignmentService(context);
            assignService.GetCancelAssigns(context, getCancelAssignsArgs);
            // 判断工作流实例是否允许被撤销：如已经被处理，则不允许撤销
            if (getCancelAssignsArgs.ProcInstCanCancelAssigns.Count == 0)
            {
                //throw new KDBusinessException("AutoCancel-003", "未找到允许撤销的工作流实例！");
                return null;
            }
            else if (getCancelAssignsArgs.ProcInstCanCancelAssigns[0].CanAbortInstance == false)
            {
                return null;
                //throw new KDBusinessException("AutoCancel-004", "提交的工作流已经被处理，不允许撤销！");
            }
            string procInstId = getCancelAssignsArgs.ProcInstCanCancelAssigns[0].ProcessInstanceId;
            // 构建操作可选参数对象：忽略交互性的警告提示
            OperateOption cancelOption = OperateOption.Create();
            cancelOption.SetIgnoreWarning(true);
            // 设置撤销原因
            cancelOption.SetVariableValue("canceldisposition", "同步OA失败！");
            // 撤销工作流实例
            IProcInstService procInstService = Kingdee.BOS.Workflow.Contracts.ServiceFactory.GetProcInstService(context);
            IOperationResult cancelResult = procInstService.AbortProcInst(
            context,
            new string[] { procInstId },
            cancelOption);
            return cancelResult;
        }
        /// <summary>
        /// 提交-审核目标单据
        /// </summary>
        /// <param name="context"></param>
        /// <param name="ids"></param>
        /// <param name="orc"></param>
        /// <param name="businessInfo"></param>
        /// <param name="isSubmitAutoAudit">是否提交后自动审核</param>
        /// <param name="isAuditFailAutoDelete">是否审核失败自动反审核删除</param>
        /// <returns></returns>
        public static bool SubmitAndAudit(Context context, HashSet<object> ids, OperateResultCollection orc, BusinessInfo businessInfo, bool isSubmitAutoAudit, bool isAuditFailAutoDelete)
        {
            OperateOption option = OperateOption.Create();
            //option.SetIgnoreWarning(true);
            //option.SetIgnoreInteractionFlag(true);
            //提交
            var submitResult = BusinessDataServiceHelper.Submit(context, businessInfo, ids.ToArray(), "Submit");
            WriteOperateResultCollection(orc, submitResult);
            if (submitResult.IsSuccess)
            {
                if (isSubmitAutoAudit)
                {
                    ids.Clear();
                    foreach (OperateResult items in submitResult.OperateResult)
                    {
                        ids.Add(items.PKValue);
                    }
                    //审核
                    var auditResult = BusinessDataServiceHelper.Audit(context, businessInfo, ids.ToArray(), null);
                    WriteOperateResultCollection(orc, auditResult);
                    if (auditResult.IsSuccess)
                    {
                        return true;
                    }
                    //审核失败，反审核单据并删除
                    else if (isAuditFailAutoDelete)
                    {
                        var unAuditResult = BusinessDataServiceHelper.UnAudit(context, businessInfo, ids.ToArray(), null);
                        WriteOperateResultCollection(orc, unAuditResult);
                        var deleteResult = BusinessDataServiceHelper.Delete(context, businessInfo, ids.ToArray());
                        WriteOperateResultCollection(orc, deleteResult);
                    }
                }
                else
                {
                    return true;
                }
            }
            //提交失败，删除单据
            else if (isAuditFailAutoDelete)
            {
                var deleteResult = BusinessDataServiceHelper.Delete(context, businessInfo, ids.ToArray());
                WriteOperateResultCollection(orc, deleteResult);
            }
            return false;
        }
        /// <summary>
        /// 将操作结果加到操作集合
        /// </summary>
        /// <param name="orc"></param>
        /// <param name="result"></param>
        public static void WriteOperateResultCollection(OperateResultCollection orc, IOperationResult result)
        {
            foreach (var item in result.OperateResult)
            {
                orc.Add(item);
            }
            if (result.ValidationErrors.Count > 0)
            {
                foreach (var err in result.ValidationErrors)
                {
                    orc.Add(new OperateResult() { Message = err.Message, MessageType = MessageType.FatalError, SuccessStatus = false });
                }
            }
            if (!result.IsSuccess && result.InteractionContext != null && !result.InteractionContext.SimpleMessage.IsNullOrEmptyOrWhiteSpace())
            {
                orc.Add(new OperateResult() { Message = result.InteractionContext.SimpleMessage, MessageType = MessageType.FatalError, SuccessStatus = false });
            }
        }
        /// <summary>
		/// 提交-审核目标单据
		/// </summary>
		/// <param name="ids"></param>
		/// <param name="orc"></param>
		/// <param name="businessInfo"></param>
		/// <returns></returns>
		public static bool SubmitAndAudit(Context context, DynamicObject data, OperateResultCollection orc, BusinessInfo businessInfo)
        {
            HashSet<object> ids = new HashSet<object>() { data["id"] };
            string documentStatus = Convert.ToString(businessInfo.GetBillStatusField().GetFieldValue(data));
            if (documentStatus.EqualsIgnoreCase("B"))
            {
                OperateOption option = OperateOption.Create();
                option.SetIgnoreWarning(true);
                option.SetIgnoreInteractionFlag(true);
                option.SetIgnoreScopeValidateFlag(true);
                //审核
                var auditResult = BusinessDataServiceHelper.Audit(context, businessInfo, ids.ToArray(), option);
                WriteOperateResultCollection(orc, auditResult);
                if (auditResult.IsSuccess)
                {
                    return true;
                }
            }
            else if (!documentStatus.EqualsIgnoreCase("C"))
            {
                //提交
                var submitResult = BusinessDataServiceHelper.Submit(context, businessInfo, ids.ToArray(), "Submit");
                WriteOperateResultCollection(orc, submitResult);
                if (submitResult.IsSuccess)
                {
                    ids.Clear();
                    foreach (var items in submitResult.SuccessDataEnity)
                    {
                        ids.Add(items["id"]);
                    }
                    OperateOption option = OperateOption.Create();
                    option.SetIgnoreWarning(true);
                    option.SetIgnoreInteractionFlag(true);
                    option.SetIgnoreScopeValidateFlag(true);
                    //审核
                    var auditResult = BusinessDataServiceHelper.Audit(context, businessInfo, ids.ToArray(), option);
                    WriteOperateResultCollection(orc, auditResult);
                    if (auditResult.IsSuccess)
                    {
                        return true;
                    }
                }
            }
            return false;
        }
        /// <summary>
        /// 通过辅助资料名称获取对象
        /// </summary>
        /// <returns></returns>
        public static DynamicObject GetAssistantDataByFilterName(Context context, string formId, string fId, string where)
        {
            DynamicObject obj = null;
            FormMetadata meta = MetaDataServiceHelper.Load(context, formId) as FormMetadata;
            QueryBuilderParemeter queryParam = new QueryBuilderParemeter();
            queryParam.FormId = formId;
            List<string> filters = new List<string>();
            filters.Add(string.Format(" FID = '{0}' ", fId));
            if (!where.IsNullOrEmptyOrWhiteSpace())
            {
                filters.Add(where);
            }
            queryParam.FilterClauseWihtKey = string.Join(" and ", filters);
            queryParam.OrderByClauseWihtKey = meta.BusinessInfo.GetForm().PkFieldName;
            var objs = BusinessDataServiceHelper.Load(context, meta.BusinessInfo.GetDynamicObjectType(), queryParam);
            if (objs.Length > 0) obj = objs.FirstOrDefault();
            return obj;
        }
        /// <summary>
		/// 获取单据或者基础资料
		/// </summary>
		/// <param name="formId">界面标识</param>
		/// <param name="number">编码</param>
		/// <returns></returns>
		public static DynamicObject GetDynamicObjectByFormIdAndNumber(Context context, string formId, object number)
        {
            DynamicObject obj = null;
            FormMetadata meta = MetaDataServiceHelper.GetFormMetaData(context, formId);
            QueryBuilderParemeter queryParam = new QueryBuilderParemeter();
            queryParam.FormId = formId;
            queryParam.FilterClauseWihtKey = string.Format(" {0}='{1}'", meta.BusinessInfo.GetForm().NumberFieldKey, number);
            var objs = BusinessDataServiceHelper.Load(context, meta.BusinessInfo.GetDynamicObjectType(), queryParam);
            if (objs.Length > 0) obj = objs.FirstOrDefault();
            return obj;
        }
        /// <summary>
        /// 获取单据或者基础资料
        /// </summary>
        /// <param name="formId">界面标识</param>
        /// <param name="fid">单据ID</param>
        /// <returns></returns>
        public static DynamicObject GetDynamicObjectByFormIdAndId(Context context, string formId, object orgNumber, string where)
        {
            DynamicObject obj = null;
            FormMetadata meta = MetaDataServiceHelper.GetFormMetaData(context, formId);

            QueryBuilderParemeter queryParam = new QueryBuilderParemeter();
            queryParam.FormId = formId;
            List<string> filters = new List<string>();

            if (meta.BusinessInfo.MainOrgField != null)
            {
                filters.Add(string.Format(" {0}.Fnumber={1} ", meta.BusinessInfo.MainOrgField.Key, orgNumber));
            }
            if (!where.IsNullOrEmptyOrWhiteSpace())
            {
                filters.Add(where);
            }
            queryParam.FilterClauseWihtKey = string.Join(" and ", filters);
            var objs = BusinessDataServiceHelper.Load(context, meta.BusinessInfo.GetDynamicObjectType(), queryParam);
            if (objs.Length > 0) obj = objs.FirstOrDefault();
            return obj;
        }
        /// <summary>
        /// 获取单据或者基础资料,根据组织编码获取某个字段的合计数
        /// </summary>
        /// <param name="formId">界面标识</param>
        /// <param name="fid">单据ID</param>
        /// <returns></returns>
        public static DynamicObject[] GetDynamicObjectByFormIdAndSum(Context context, string formId, object orgNumber, string where)
        {
            //DynamicObject obj = null;
            FormMetadata meta = MetaDataServiceHelper.GetFormMetaData(context, formId);

            QueryBuilderParemeter queryParam = new QueryBuilderParemeter();
            queryParam.FormId = formId;
            List<string> filters = new List<string>();

            if (meta.BusinessInfo.MainOrgField != null)
            {
                filters.Add(string.Format(" {0}.Fnumber={1} ", meta.BusinessInfo.MainOrgField.Key, orgNumber));
            }
            if (!where.IsNullOrEmptyOrWhiteSpace())
            {
                filters.Add(where);
            }
            queryParam.FilterClauseWihtKey = string.Join(" and ", filters);
            var objs = BusinessDataServiceHelper.Load(context, meta.BusinessInfo.GetDynamicObjectType(), queryParam);
            //if (objs.Length > 0) obj = objs.FirstOrDefault();
            return objs;
        }
        /// <summary>
        /// 获取单据或者基础资料
        /// </summary>
        /// <param name="formId">界面标识</param>
        /// <param name="fid">单据ID</param>
        /// <returns></returns>
        public static DynamicObject GetDynamicObjectByFormIdAndId(Context context, string formId, object fid)
        {
            DynamicObject obj = null;
            FormMetadata meta = MetaDataServiceHelper.GetFormMetaData(context, formId);
            QueryBuilderParemeter queryParam = new QueryBuilderParemeter();
            queryParam.FormId = formId;
            queryParam.FilterClauseWihtKey = string.Format(" {0}='{1}'", meta.BusinessInfo.GetForm().PkFieldName, fid);
            var objs = BusinessDataServiceHelper.Load(context, meta.BusinessInfo.GetDynamicObjectType(), queryParam);
            if (objs.Length > 0) obj = objs.FirstOrDefault();
            return obj;
        }
        /// <summary>
        /// 判断数据对象是否包含实体属性
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool IsContainsKey(DynamicObject obj, string key)
        {
            bool b = false;
            DynamicPropertyCollection p = obj.DynamicObjectType.Properties;
            if (p != null && p.Count > 0)
            {
                var findRows = p.ToArray().Where(w => w.Name.EqualsIgnoreCase(key));
                if (findRows != null && findRows.Count() > 0)
                {
                    b = true;
                }
            }
            return b;
        }
        /// <summary>
        /// 创建单据视图
        /// </summary>
        /// <param name="context">上下文</param>
        /// <param name="formId">单据标识ID</param>
        /// <returns></returns>
        public static IBillView CreateBillView(Context context, string formId)
        {
            // 读取物料的元数据
            FormMetadata meta = MetaDataServiceHelper.Load(context, formId) as FormMetadata;
            Form form = meta.BusinessInfo.GetForm();

            // 创建用于引入数据的单据view
            Type type = Type.GetType("Kingdee.BOS.Web.Import.ImportBillView,Kingdee.BOS.Web");
            var billView = (IDynamicFormViewService)Activator.CreateInstance(type);
            // 开始初始化billView：
            // 创建视图加载参数对象，指定各种参数，如FormId, 视图(LayoutId)等
            BillOpenParameter openParam = CreateOpenParameter(context, meta);
            // 动态领域模型服务提供类，通过此类，构建MVC实例
            var provider = form.GetFormServiceProvider();
            billView.Initialize(openParam, provider);
            return billView as IBillView;
        }
        private static BillOpenParameter CreateOpenParameter(Context context, FormMetadata meta)
        {
            Form form = meta.BusinessInfo.GetForm();
            // 指定FormId, LayoutId
            BillOpenParameter openParam = new BillOpenParameter(form.Id, meta.GetLayoutInfo().Id);
            // 数据库上下文
            openParam.Context = context;
            // 本单据模型使用的MVC框架
            openParam.ServiceName = form.FormServiceName;
            // 随机产生一个不重复的PageId，作为视图的标识
            openParam.PageId = Guid.NewGuid().ToString();
            // 元数据
            openParam.FormMetaData = meta;
            // 界面状态：新增 (修改、查看)
            openParam.Status = OperationStatus.ADDNEW;
            // 单据主键：本案例演示新建物料，不需要设置主键
            openParam.PkValue = null;
            // 界面创建目的：普通无特殊目的 （为工作流、为下推、为复制等）
            openParam.CreateFrom = CreateFrom.Default;
            // 基础资料分组维度：基础资料允许添加多个分组字段，每个分组字段会有一个分组维度
            // 具体分组维度Id，请参阅 form.FormGroups 属性
            openParam.GroupId = "";
            // 基础资料分组：如果需要为新建的基础资料指定所在分组，请设置此属性
            openParam.ParentId = 0;
            // 单据类型
            openParam.DefaultBillTypeId = "";
            // 业务流程
            openParam.DefaultBusinessFlowId = "";
            // 主业务组织改变时，不用弹出提示界面
            openParam.SetCustomParameter("ShowConfirmDialogWhenChangeOrg", false);
            // 插件
            List<AbstractDynamicFormPlugIn> plugs = form.CreateFormPlugIns();
            openParam.SetCustomParameter(FormConst.PlugIns, plugs);
            PreOpenFormEventArgs args = new PreOpenFormEventArgs(context, openParam);
            foreach (var plug in plugs)
            {// 触发插件PreOpenForm事件，供插件确认是否允许打开界面
                plug.PreOpenForm(args);
            }
            if (args.Cancel == true)
            {// 插件不允许打开界面
                // 本案例不理会插件的诉求，继续....
            }
            // 返回
            return openParam;
        }
        /// <summary>
        /// 条件表达式解析用这个
        /// </summary>
        /// <param name="view">单据界面视图</param>
        /// <param name="rowIndex">行号</param>
        /// <param name="entityKey">单据体标识</param>
        /// <param name="pyExpression">表达式字符串</param>
        /// <returns></returns>
        public static object analysisConditionalExpression(IBillView view, int rowIndex, string entityKey, string pyExpression)
        {
            if (view == null)
            {
                return null;
            }
            try
            {
                if (entityKey.IsNullOrEmptyOrWhiteSpace())
                {
                    entityKey = view.Model.BusinessInfo.Entrys[0].Key;
                }
                ExpressionKind kind = ExpressionKind.Expression;
                Kingdee.BOS.Scripting.BOSExpression expression = new Kingdee.BOS.Scripting.BOSExpression(pyExpression, kind, null, false);
                ExpressionContext expContext = GetExpContext(view, entityKey, rowIndex);
                object result = CalcExprParser.DefaultEvaluator.Run(expression, expContext);

                return result;
            }
            catch (Exception ex)
            {
                string msg = string.Format("单据【{0}】【{1}】的表达式【{2}】计算失败！", view.BusinessInfo.GetForm().Name, entityKey, pyExpression);
                throw new Exception(msg + ex.Message);
            }
        }

        private static ExpressionContext GetExpContext(IBillView billView, string entityKey, int rowIndex)
        {
            Kingdee.BOS.Orm.DataEntity.DynamicObject activeRow = FormBusinessServiceUtil.GetActiveRow(billView.Model, entityKey, rowIndex);
            BOSDynamicRow bosdynamicRow = new BOSDynamicRow(activeRow, entityKey, billView.Model);
            object obj = new System.Dynamic.ExpandoObject();
            if (GetExpContextObject.p__Site3 == null)
            {
                GetExpContextObject.p__Site3 = CallSite<Func<CallSite, object, BusinessInfo, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, "ActiveInfo", typeof(KAndOSysSynTool), new CSharpArgumentInfo[]
                {
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null)
                }));
            }
            GetExpContextObject.p__Site3.Target(GetExpContextObject.p__Site3, obj, billView.BillBusinessInfo);
            if (GetExpContextObject.p__Site4 == null)
            {
                GetExpContextObject.p__Site4 = CallSite<Func<CallSite, object, BOSDynamicRow, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, "ActiveObject", typeof(KAndOSysSynTool), new CSharpArgumentInfo[]
                {
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null)
                }));
            }
            GetExpContextObject.p__Site4.Target(GetExpContextObject.p__Site4, obj, bosdynamicRow);
            FunctionManage functionLib = FunctionServiceHelper.GetFunctionLib(billView.Context);
            if (GetExpContextObject.p__Site5 == null)
            {
                GetExpContextObject.p__Site5 = CallSite<Func<CallSite, Type, Context, object, FunctionManage, BOSFuncExpressionContext>>.Create(Binder.InvokeConstructor(CSharpBinderFlags.None, typeof(KAndOSysSynTool), new CSharpArgumentInfo[]
                {
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType | CSharpArgumentInfoFlags.IsStaticType, null),
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
                    CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null)
                }));
            }
            return GetExpContextObject.p__Site5.Target(GetExpContextObject.p__Site5, typeof(BOSFuncExpressionContext), billView.Context, obj, functionLib).BindGetField(new TryGetValueHandler(bosdynamicRow.TryGetMember)).BindSetField(new TrySetValueHandler(bosdynamicRow.TrySetMember));
        }

        public static string GetAttachmentBase64(Context context, DynamicObject attachment, UpDownloadService fileService)
        {
            //获取同步设置和URL
            DynamicObject setting = KAndOSysSynTool.GetKToOSysSynSetting(context, "", 0);
            string oaUrl = Convert.ToString(setting["OSysURL"]);
            string FOaFilesUrl = Convert.ToString(setting["FOaFilesUrl"]);
            string appkey = Convert.ToString(setting["FOSysURL2"]);
            string workcode = KAndOSysSynTool.GetWorkCode(context, context.UserId.ToString());
            if (attachment == null)
            {
                return "";
            }
            //金蝶编码
            string billNo = Convert.ToString(attachment["BillNo"]);
            //文件ID
            string fileId = Convert.ToString(attachment["FileId"]);
            //从文件服务器
            if (!fileId.IsNullOrEmptyOrWhiteSpace())
            {
                ////创建日期
                //DateTime createDate = Convert.ToDateTime(attachment["CreateTime"]);
                ////文件后缀
                //string extName = Convert.ToString(attachment["ExtName"]);
                //名称
                string name = Convert.ToString(attachment["AttachmentName"]);
                ////备注
                //string note = Convert.ToString(attachment["AttachmentDes"]);

                TFileInfo tFile = new TFileInfo() { FileId = fileId, CTX = context };
                byte[] fileData = fileService.GetFileData(tFile);
                //var url = fileService.GetFileServiceServerUrl(tFile);
                // 获取或创建临时目录
                string path = HttpContext.Current.Server.MapPath(KeyConst.TEMPFILEPATH);
                //不存在则创建文件目录
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                // 生成一个临时文件名
                string fileName = Path.Combine(path, name);
                if (File.Exists(fileName))
                {
                    File.Delete(fileName);
                }
                TFileInfo dFile = new TFileInfo() { FileId = fileId, CTX = context, FilePath = fileName };
                var dfiles = fileService.DownloadSaveLocal(dFile);

                string url = oaUrl + FOaFilesUrl;
                var client = new RestClient(url);
                client.Timeout = -1;
                var request = new RestRequest(Method.POST);
                request.AddHeader("appkey", appkey);
                request.AddHeader("workcode", workcode);
                request.AddParameter("category", "470");//每个OA环境可能会变，测试是89 正式是470
                request.AddFile("file", fileName);
                request.AddParameter("name", name);
                IRestResponse response = client.Execute(request);
                var res = response.Content;
                var oafilRes = JsonConvert.DeserializeObject<OaFilesResult>(res);
                //文件大小
                //long fileSize = fileData.Length;
                //string str = Convert.ToBase64String(fileData);
                string str = oafilRes.data.fileid;
                return str;
            }
            //从数据库
            else
            {
                byte[] fileData = (byte[])attachment["Attachment"];
                string str = Convert.ToBase64String(fileData);
                return str;
            }
        }

        public static DynamicObjectCollection GetTuiSongRen(Context context)
        {
            string sql = string.Format(@"/*dialect*/ 
            SELECT T0.FGROUP, 
                   T2.FNAME
            FROM YCVN_t_Cust_Entry100018 T0
                 JOIN YCVN_t_0001 T1 ON T1.FEntryID = T0.FEntryID
                 JOIN T_HR_EMPINFO_L T2 ON T2.FID = T1.F_YG_TSR
                                           AND T2.FLOCALEID = 2052 ");
            DynamicObjectCollection doc = DBUtils.ExecuteDynamicObject(context, sql);
            return doc;
        }

        public static string GetTimestamp()
        {
            // 获取当前时间
            DateTime currentTime = DateTime.UtcNow;

            // Unix时间戳起始时间
            DateTime unixStartTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);

            // 计算当前时间与Unix起始时间的时间间隔
            TimeSpan elapsedTime = currentTime - unixStartTime;

            // 将时间间隔的总秒数作为Unix时间戳
            //long timestamp = (long)elapsedTime.TotalSeconds;
            long timestamp = (long)elapsedTime.TotalMilliseconds;
            return timestamp.ToString();
        }

        [CompilerGenerated]
        private static class GetExpContextObject
        {
            // Token: 0x040017EC RID: 6124
            public static CallSite<Func<CallSite, object, BusinessInfo, object>> p__Site3;

            // Token: 0x040017ED RID: 6125
            public static CallSite<Func<CallSite, object, BOSDynamicRow, object>> p__Site4;

            // Token: 0x040017EE RID: 6126
            public static CallSite<Func<CallSite, Type, Context, object, FunctionManage, BOSFuncExpressionContext>> p__Site5;
        }
    }
}
